package com.ruoyi.tester.swagger;

import com.ruoyi.tester.domain.TesterInterface;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author SongJun
 * @description TODO:
 * @date 2022/5/24 11:43
 */
public class SwaggerParserV3 implements SwaggerParser {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private JSONObject root;
    private JSONObject paths;

    public SwaggerParserV3(String apiDocs){
        root = new JSONObject(apiDocs);
        paths = root.getJSONObject("paths");
    }

    public List<TesterInterface> parse(){
        List<TesterInterface> ret = new ArrayList<>();
        for(String mapping : paths.keySet()){
            JSONObject path = paths.getJSONObject(mapping);
            for (String httpMethod : path.keySet()){
                TesterInterface testerInterface = new TesterInterface();
                testerInterface.setDesc("");
                testerInterface.setQueryParam("");
                testerInterface.setPathParam("");
                testerInterface.setBodyParam("");
                testerInterface.setContentType("");
                ret.add(testerInterface);

                JSONObject itf = path.getJSONObject(httpMethod);
                testerInterface.setMapping(mapping);
                testerInterface.setHttpMethod(httpMethod.toUpperCase());
                testerInterface.setDesc(itf.getString("summary"));

                if(itf.has("parameters")){
                    JSONObject queryParam = null;
                    JSONObject bodyParam = null;
                    JSONObject pathParam = null;
                    JSONArray parameters = itf.getJSONArray("parameters");
                    for (int i=0; i<parameters.length(); i++){
                        JSONObject field = parameters.getJSONObject(i);
                        String fieldName = field.getString("name");
                        if(fieldName.contains("[0].")){
                            //query参数含有子集合对象则忽略
                            continue;
                        }
                        String fieldType = field.getJSONObject("schema").getString("type");
                        Object fieldValue = null;
                        if("array".equals(fieldType)){
                            String subFieldType = field.getJSONObject("schema").getJSONObject("items").getString("type");
                            Object subFieldValue = mockValue(subFieldType);
                            fieldValue = Arrays.asList(subFieldValue);
                        } else {
                            fieldValue = mockValue(fieldType);
                        }
                        String in = field.getString("in");
                        if("query".equals(in)){
                            if("form".equals(field.getString("style")) && "post".equals(httpMethod)){
                                bodyParam = bodyParam == null ? new JSONObject() : bodyParam;
                                bodyParam.put(fieldName, fieldValue);
                            } else {
                                queryParam = queryParam == null ? new JSONObject() : queryParam;
                                queryParam.put(fieldName, fieldValue);
                            }
                        } else if("path".equals(in)){
                            pathParam = pathParam == null ? new JSONObject() : pathParam;
                            pathParam.put(fieldName, fieldValue);
                        }
                    }
                    if(queryParam != null ){
                        testerInterface.setQueryParam(queryParam.toString());
                    }
                    if(pathParam != null ){
                        testerInterface.setPathParam(pathParam.toString());
                    }
                    if(bodyParam != null ){
                        testerInterface.setBodyParam(bodyParam.toString());
                    }
                }
                if(itf.has("requestBody")){
                    JSONObject contentTypeJson = itf.getJSONObject("requestBody").getJSONObject("content");
                    for (String k : contentTypeJson.keySet()){
                        testerInterface.setContentType(k);
                        JSONObject schema = contentTypeJson.getJSONObject(k).getJSONObject("schema");

                        if(schema.has("items")){
                            String refPath = schema.getJSONObject("items").getString("$ref");
                            Object mock = parseRefMock(refPath);
                            String fieldType = schema.getString("type");
                            if("array".equals(fieldType)){
                                mock = Arrays.asList(mock);
                            }
                            testerInterface.setBodyParam(mock.toString());
                            testerInterface.setBodyParam(mock.toString());
                        } else {
                            String refPath = schema.getString("$ref");
                            Object mock = parseRefMock(refPath);
                            testerInterface.setBodyParam(mock.toString());
                            testerInterface.setBodyParam(mock.toString());
                        }
                    }
                }
            }
        }
        return ret;
    }

    private Object parseRefMock(String refPath){
        JSONObject mockParam = new JSONObject();
        String[] pathArray = refPath.split("/");
        JSONObject temp = null;
        for(int i=0; i<pathArray.length; i++){
            if("#".equals(pathArray[i])){
                temp = root;
            } else {
                temp = temp.getJSONObject(pathArray[i]);
            }
        }
        JSONObject properties = temp.getJSONObject("properties");
        for (String fieldName : properties.keySet()){
            JSONObject field = properties.getJSONObject(fieldName);
            Object fieldValue = null;
            if(field.has("$ref")){
                fieldValue = parseRefMock(field.getString("$ref"));
            } else {
                String fieldType = field.getString("type");
                if ("array".equals(fieldType)) {
                    JSONObject subField = field.getJSONObject("items");
                    if(subField.has("$ref")){
                        Object subFieldValue = parseRefMock(subField.getString("$ref"));
                        fieldValue = Arrays.asList(subFieldValue);
                    } else {
                        String subFieldType = subField.getString("type");
                        Object subFieldValue = mockValue(subFieldType);
                        fieldValue = Arrays.asList(subFieldValue);
                    }
                } else {
                    fieldValue = mockValue(fieldType);
                }
            }
            mockParam.put(fieldName, fieldValue);
        }
        return mockParam;
    }

//    private String getRefPath(JSONObject json){
//        for (String k : json.keySet()){
//            if("$ref".equals(k)){
//                return json.getString(k);
//            } else {
//                Object sub = json.get(k);
//                if(sub instanceof JSONObject){
//                    return getRefPath((JSONObject) sub);
//                }
//            }
//        }
//        return null;
//    }

    private Object mockValue(String type){
        Object v = null;
        if("integer".equals(type) || "number".equals(type)){
            v = 13579;
        } else if("string".equals(type)){
            v = "abcde";
        } else if("boolean".equals(type)){
            v = false;
        }
        return v;
    }


//    private Object componentsRef(String ref){
//        return null;
//    }
}
